#ifndef __MY_UTIL__
#define __MY_UTIL__

#include <iostream>
#include <fstream> // 文件相关操作函数
#include <string>
#include <vector>
#include <experimental/filesystem> // 引入文件系统操作的功能,C++17被引入标准库
#include <sys/stat.h>              // 包含文件信息结构体struct stat，通过stat结构体获取文件信息

namespace cloud
{
    namespace fs = std::experimental::filesystem;
    // 文件工具
    class FileUtil
    {
    private:
        std::string _filename; // 包含文件路径的文件名

    public:
        FileUtil(const std::string& filename)
            : _filename(filename)
        {
        }

        // 删除文件
        bool Remove()
        {
            if (this->Exists() == false)
            {
                return true;
            }
            remove(_filename.c_str());
            return true;
        }

        // 判断文件是否存在
        bool Exists()
        {
            return fs::exists(_filename);
        }

        // 获取文件大小:1.直接通过stat结构体获取
        // 2.使用seekg()函数更改文件读取指针位置到文件末尾，再用tellg()函数获取文件指针位置得到文件大小，最后更改文件读取指针到文件起始位置
        size_t FileSize()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0) // 通过stat结构体获取文件大小
            {
                std::cout << "get file size failed!\n";
                return -1;
            }
            return st.st_size;
        }

        // 获取文件最后修改时间
        time_t LastMTime()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "get file last modify time failed!\n";
                return -1;
            }
            return st.st_mtime;
        }

        // 获取文件最后访问时间
        time_t LastATime()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "get file last access time failed!\n";
                return -1;
            }
            return st.st_atime;
        }

        // 获取不包含文件路径的文件名
        std::string FileName()
        {
            // ./a/b/c/test.txt
            size_t pos = _filename.find_last_of("\\");// windowns下路径分隔符为"\\"
            if (pos == std::string::npos)
            {
                return _filename;
            }
            return _filename.substr(pos + 1); // 左闭右开
        }

        // 获取指定大小范围的文件数据
        bool GetPosLen(std::string* body, size_t pos, size_t len)
        {
            size_t fsize = this->FileSize();
            if (pos + len > fsize)
            {
                std::cout << "get file len is error\n";
                return false;
            }
            std::ifstream ifs;
            ifs.open(_filename, std::ios::binary);
            if (ifs.is_open() == false)
            {
                std::cout << "read open file failed!\n";
                return false;
            }
            ifs.seekg(pos, std::ios::beg); // 更该文件读取指针到pos位置
            body->resize(len);
            ifs.read(&(*body)[0], len); // (&*(body)[0])获取string对象的第一个元素位置，(&*(body))是不可行的，string对象还包含其它成员
            if (ifs.good() == false)    // 判断文件状态
            {
                std::cout << "get file content failed\n";
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }

        // 获取文件全部数据
        bool GetContent(std::string* body)
        {
            size_t fsize = this->FileSize();
            return GetPosLen(body, 0, fsize);
        }

        // 设置问文件内容
        bool SetContent(const std::string& body)
        {
            std::ofstream ofs;
            ofs.open(_filename, std::ios::binary); // ofstream输出文件流open()打开文件时，若文件不存在会创建文件
            if (ofs.is_open() == false)
            {
                std::cout << "write open file failed!\n";
                return false;
            }
            ofs.write(&body[0], body.size());
            if (ofs.good() == false)
            {
                std::cout << "write file content failed!\n";
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }

        // 创建目录
        bool CreateDirectory()
        {
            if (this->Exists())
            {
                return true;
            }
            return fs::create_directories(_filename);
        }

        // 浏览目录
        // ./backdir/1.txt
        bool ScanDirectory(std::vector<std::string>* arry)
        {
            this->CreateDirectory();
            for (auto& p : fs::directory_iterator(_filename))
            {
                if (fs::is_directory(p) == true) // 如果该目录下存在目录，跳过当前循环，只插入文件相对路径
                {
                    continue;
                }
                // relative_path 相对文件路径
                arry->push_back(fs::path(p).relative_path().string());
            }
            return true;
        }
    };


}

#endif
